﻿using mode;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Weave.TCPClient;

namespace AutoUpPrj
{

    public class PrjAutoUp {

        /// <summary>
        /// 开始更新最新版本并返回成功更新的最新版本号
        /// </summary>
        /// <param name="prjname"></param>
        /// <param name="creversion"></param>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public int startUpdate(string prjname,int creversion, string ip,int port)
        {
            string path2 = System.Environment.CurrentDirectory;
            int maxversion = creversion;
            synhelper syn = new synhelper(ip, port);
            int[] listvers = syn.getversion(prjname, creversion);
            foreach (var version in listvers)
            {
                string[] files = syn.getfilesByversion(prjname, version);
                bool gg = true;
                foreach (var file in files)
                {
                    filestream fstream=syn.GetFilestream(prjname, version, file);
                    string pat = Path.GetDirectoryName(path2 + fstream.Filename);
                    if (!Directory.Exists(pat))
                    {
                        Directory.CreateDirectory(pat);
                    }
                    FileStream fss = File.Create(path2+fstream.Filename + ".tmp");
                    if (fstream.Maxlen == 0)
                        fstream.Maxlen = 1;
                    long offset = fss.Seek(fstream.Maxlen - 1, SeekOrigin.Begin);
                    fss.WriteByte(new byte());

                    fss.Close();
                    long count = fstream.Maxlen % (1024 * 4) == 0 ? fstream.Maxlen / (1024 * 4) : (fstream.Maxlen / (1024 * 4)) + 1;
                    bool bb= recfile(new byte[count], ip, port, prjname, version, file);
                    if (!bb)
                        gg = false;
                    


                }
                if(gg)
                    maxversion = version;
            }
            return maxversion;
        }

        public bool recfile(byte[] State, string ip, int port, string prjname,int version,string file)
        {
            string path2 = System.Environment.CurrentDirectory;
            P2Pclient pclient = new P2Pclient(DataType.bytes);
            pclient.ReceiveServerEventbit += Pclient_ReceiveServerEventbit;
            bool login = pclient.Start(ip, port, false);

            if (!login)
            {
                Console.WriteLine("服务器无法连接");
                return false;
            }
            prjversion prj = new prjversion();
            prj.name = prjname;
            prj.version = version;
            prj.file = file;
            string str = Newtonsoft.Json.JsonConvert.SerializeObject(prj);
            pclient.Send(0x04, str);

            void Pclient_ReceiveServerEventbit(byte command, byte[] data)
            {
                if (command != 0x04)
                    return;
                MemoryStream ms = new MemoryStream(data);
                ms.Position = 0;
                BinaryReader br = new BinaryReader(ms);
                int index = br.ReadInt32();
                int len= br.ReadInt32();
                byte[] dataStream = br.ReadBytes(len);
                System.IO.FileStream fi = new FileStream(path2 + file + ".tmp", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); //System.IO.File.Open(path2+file + ".tmp", FileMode.Open, FileAccess.Write, FileShare.Write);
                fi.Seek(index * 1024 * 4, SeekOrigin.Begin);
                fi.Write(dataStream, 0, len);
                fi.Close();
                State[index] = 1;
                ms.Close();
                br.Close();
            }
            while (true)
            {
                DateTime dt = DateTime.Now;
                int prejindu = 0;
                int jindu = 0;
                int zongjindu = State.Length;
                foreach (var stast in State)
                    if (stast == 1)
                        jindu += 1;

                if (prejindu != jindu)
                {
                    dt = DateTime.Now;
                }
                if ((DateTime.Now - dt).TotalSeconds > 10)
                {
                    if (!pclient.Isline)
                    {
                        pclient.Stop();
                        return false;
                    }
                       
                    for(var i=0;i<  State.Length;i++)
                        if (State[i] == 0)
                        {
                            //发送到服务端，让服务端重发此段内容
                             prj = new prjversion();
                            prj.name = prjname;
                            prj.version = version;
                            prj.file = file;
                            prj.index = i;
                             str = Newtonsoft.Json.JsonConvert.SerializeObject(prj);
                            pclient.Send(0x05, str);
                        } 
                    //检查哪里断流了
                }
                prejindu = jindu;
                Console.Clear();
                Console.WriteLine(file + "更新进度：" + (jindu / zongjindu) * 100 + "%");
                if (jindu == zongjindu)
                {
                    try
                    {
                        File.Delete(path2 + file);
                        File.Move(path2+file + ".tmp", path2+ file);
                        File.Delete(path2+file + ".tmp");
                    }
                    catch { }
                    pclient.Stop();
                    return true;
                }
                System.Threading.Thread.Sleep(1000);
            }

        }

     
    }

  public  class synhelper
    {
        Weave.TCPClient.P2Pclient pclient ;
        string ip = "";
        int port = 0;

        public synhelper(string _ip,int _port)
        {
            //pclient.ReceiveServerEventbit += Pclient_ReceiveServerEventbit;
            ip = _ip;
            port = _port;
        }
        byte[] temp = new byte[0];
        bool retstats = false;
        private void Pclient_ReceiveServerEventbit(byte command, byte[] data)
        {
            switch (command)
            {
                case 0x01:
                    retstats = true;
                    temp = data;
                  break;
                case 0x02:
                    retstats = true;
                    temp = data;
                    break;
                case 0x03:
                    retstats = true;
                    temp = data;
                    break;
                case 0xfb:
                    retstats = true;
                    temp = null;
                    break;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public filestream GetFilestream(string prjname, int creversion,string filenmae)
        {

            prjversion prj = new prjversion();
            prj.name = prjname;
            prj.version = creversion;
            prj.file = filenmae;
            string str = Newtonsoft.Json.JsonConvert.SerializeObject(prj);
            byte[] ret = send(0x03, System.Text.Encoding.UTF8.GetBytes(str));
            if (ret != null)
                return Newtonsoft.Json.JsonConvert.DeserializeObject<filestream>(Encoding.UTF8.GetString(ret));
            else
                return null;
        }
        /// <summary>
        /// 返回带升级版本
        /// </summary>
        /// <param name="prjname">项目名称</param>
        /// <param name="creversion"></param>
        /// <returns></returns>
        public int[] getversion(string prjname,int creversion)
        {
            prjversion prj = new prjversion();
            prj.name = prjname;
            prj.version = creversion;
            string str= Newtonsoft.Json.JsonConvert.SerializeObject(prj);
           byte[] ret=  send(0x01, System.Text.Encoding.UTF8.GetBytes(str));
            if (ret != null)
                return Newtonsoft.Json.JsonConvert.DeserializeObject<int[]>(Encoding.UTF8.GetString(ret));
            else
               return new int[0];
        }
        /// <summary>
        /// 根据版本获取待升级文件
        /// </summary>
        /// <param name="prjname"></param>
        /// <param name="creversion"></param>
        /// <returns></returns>
        public string[] getfilesByversion(string prjname, int creversion)
        {
            prjversion prj = new prjversion();
            prj.name = prjname;
            prj.version = creversion;
            string str = Newtonsoft.Json.JsonConvert.SerializeObject(prj);
            byte[] ret = send(0x02, System.Text.Encoding.UTF8.GetBytes(str));
            if (ret != null)
                return Newtonsoft.Json.JsonConvert.DeserializeObject<string[]>(Encoding.UTF8.GetString(ret));
            else
                return new string[0];
        }

        byte[] send(byte command, byte[] data)
        {
            pclient = new Weave.TCPClient.P2Pclient(Weave.TCPClient.DataType.bytes);
            pclient.ReceiveServerEventbit += Pclient_ReceiveServerEventbit;
            bool login= pclient.Start(ip, port, false);
            if (!login)
                return null;
            retstats = false;
            DateTime dt = DateTime.Now;
            if (pclient.Send(command, data))
            {
                while (!retstats)
                {

                    if ((DateTime.Now - dt).TotalSeconds > 10)
                    {
                        pclient.Stop();
                        return null;
                    }
                    System.Threading.Thread.Sleep(10);
                }
                pclient.Stop();
                return temp;
            }
            else
            {
                pclient.Stop();
                return null;
            }
         
        }


    }
}
